home *** CD-ROM | disk | FTP | other *** search
/ Aminet 20 / Aminet 20 (1997)(GTI - Schatztruhe)[!][Aug 1997].iso / Aminet / comm / www / HTP.lha / HTP / source / varstore.c < prev    next >
C/C++ Source or Header  |  1997-06-21  |  9KB  |  426 lines

  1. /*
  2. //
  3. // varstore.c
  4. //
  5. // Variable store functions (implemented with a simple hash table)
  6. //
  7. // Copyright (c) 1995-96 Jim Nelson.  Permission to distribute
  8. // granted by the author.  No warranties are made on the fitness of this
  9. // source code.
  10. // Amiga version - 1997 - Geert Bevin
  11. //
  12. */
  13.  
  14. #include "htp.h"
  15.  
  16. /* statistics for performance measurement */
  17. #if DEBUG
  18. uint variableLookups = 0;
  19. uint variableCacheHits = 0;
  20. uint variableStringCompares = 0;
  21. uint variableMissedStringCompares = 0;
  22. uint variableHashCalcs = 0;
  23. #endif
  24.  
  25. /* !! dont primes contribute to a more evenly distributed hash table? */
  26. /* need to check Knuth ... */
  27. #define HASH_TABLE_SIZE             (53)
  28.  
  29. /*
  30. // generates an index into the hash table from the string
  31. */
  32. uint StringToHashTableIndex(const char *name)
  33. {
  34.     uint hash;
  35.     uint ctr;
  36.  
  37.     if(name == NULL)
  38.     {
  39.         return 0;
  40.     }
  41.  
  42.     #if DEBUG
  43.     variableHashCalcs++;
  44.     #endif
  45.  
  46.     hash = 0;
  47.     ctr = 0;
  48.     while(*name != NUL)
  49.     {
  50.         /* uppercase the chars before hashing because names are case-insensitive */
  51.         /* shift left to give a broader distribution in the hash table */
  52.         hash += (uint) toupper(*name++) << (ctr++ & 0x03);
  53.     }
  54.  
  55.     return (hash % HASH_TABLE_SIZE);
  56. }
  57.  
  58. BOOL InitializeVariableStore(VARSTORE *varstore)
  59. {
  60.     assert(varstore != NULL);
  61.  
  62.     /* allocate the hash table */
  63.     varstore->variableHashTable = AllocMemory(sizeof(VARIABLE *) * HASH_TABLE_SIZE);
  64.     if(varstore->variableHashTable == NULL)
  65.     {
  66.         DEBUG_PRINT(("out of memory trying to allocate variable hash table"));
  67.         return FALSE;
  68.     }
  69.     memset(varstore->variableHashTable, 0, sizeof(VARIABLE *) * HASH_TABLE_SIZE);
  70.  
  71.     /* initialize the rest of the store */
  72.     varstore->parent = NULL;
  73.     varstore->child = NULL;
  74.     varstore->lastVariable = NULL;
  75.  
  76.     return TRUE;
  77. }
  78.  
  79. void DestroyVariableStore(VARSTORE *varstore)
  80. {
  81.     /* destroy all children as well ... this function doesn't simply "unlink" */
  82.     /* the current store from the linked list */
  83.     while(varstore != NULL)
  84.     {
  85.         /* unlink from parent */
  86.         if(varstore->parent != NULL)
  87.         {
  88.             varstore->parent->child = NULL;
  89.             varstore->parent = NULL;
  90.         }
  91.  
  92.         /* destroy all variables in this store */
  93.         ClearVariableList(varstore);
  94.  
  95.         /* free the hash table memory */
  96.         FreeMemory(varstore->variableHashTable);
  97.         varstore->variableHashTable = NULL;
  98.  
  99.         /* destroy all child scopes as well */
  100.         varstore = varstore->child;
  101.     }
  102. }
  103.  
  104. BOOL StoreVariable(VARSTORE *varstore, const char *name, const char *value,
  105.     uint type, uint flag, void *param, VAR_DESTRUCTOR destructor)
  106. {
  107.     VARIABLE *variable;
  108.     VARIABLE *ptr;
  109.     uint index;
  110.  
  111.     assert(varstore != NULL);
  112.     assert(name != NULL);
  113.  
  114.     /* remove any variable with the same name in the store */
  115.     RemoveVariable(varstore, name);
  116.  
  117.     /* allocate space for the variable structure */
  118.     if((variable = AllocMemory(sizeof(VARIABLE))) == NULL)
  119.     {
  120.         DEBUG_PRINT(("unable to allocate memory for new variable"));
  121.         return FALSE;
  122.     }
  123.  
  124.     /* copy in the variable's name */
  125.     StringCopy(variable->name, name, MAX_VARNAME_LEN);
  126.  
  127.     /* copy in the variable's value, if any */
  128.     if(value != NULL)
  129.     {
  130.         StringCopy(variable->value, value, MAX_VARVALUE_LEN);
  131.     }
  132.  
  133.     /* set flags and destructor pointer */
  134.     variable->type = type;
  135.     variable->flag = flag;
  136.     variable->param = param;
  137.     variable->destructor = destructor;
  138.     variable->next = NULL;
  139.  
  140.     /* insert into the hash table */
  141.     index = StringToHashTableIndex(name);
  142.     ptr = varstore->variableHashTable[index];
  143.     varstore->variableHashTable[index] = variable;
  144.     if(ptr != NULL)
  145.     {
  146.         /* the slot has been previously hashed to a different variable, */
  147.         /* inserted new item at beginning of list, add rest to end */
  148.         variable->next = ptr;
  149.     }
  150.  
  151.     /* put this new variable into the last-used cache */
  152.     varstore->lastVariable = variable;
  153.  
  154.     return TRUE;
  155. }   
  156.  
  157. static VARIABLE *FindVariable(VARSTORE *varstore, const char *name)
  158. {
  159.     VARIABLE *ptr;
  160.  
  161.     assert(varstore != NULL);
  162.     assert(name != NULL);
  163.  
  164.     #if DEBUG
  165.     variableLookups++;
  166.     #endif
  167.  
  168.     /* check the last referenced variable first */
  169.     if(varstore->lastVariable != NULL)
  170.     {
  171.         #if DEBUG
  172.         variableStringCompares++;
  173.         #endif
  174.  
  175.         if(stricmp(varstore->lastVariable->name, name) == 0)
  176.         {
  177.             #if DEBUG
  178.             variableCacheHits++;
  179.             #endif
  180.  
  181.             return varstore->lastVariable;
  182.         }
  183.  
  184.         #if DEBUG
  185.         variableMissedStringCompares++;
  186.         #endif
  187.     }
  188.  
  189.     ptr = varstore->variableHashTable[StringToHashTableIndex(name)];
  190.     while(ptr != NULL)
  191.     {
  192.         #if DEBUG
  193.         variableStringCompares++;
  194.         #endif
  195.  
  196.         if(stricmp(ptr->name, name) == 0)
  197.         {
  198.             /* cache this variable for next time */
  199.             varstore->lastVariable = ptr;
  200.  
  201.             return ptr;
  202.         }
  203.  
  204.         #if DEBUG
  205.         variableMissedStringCompares++;
  206.         #endif
  207.  
  208.         ptr = ptr->next;
  209.     }
  210.  
  211.     /* check all parent stores as well */
  212.     if(varstore->parent != NULL)
  213.     {
  214.         return FindVariable(varstore->parent, name);
  215.     }
  216.  
  217.     return NULL;
  218. }   
  219.  
  220. const char *GetVariableValue(VARSTORE *varstore, const char *name)
  221. {
  222.     VARIABLE *variable;
  223.  
  224.     if(name != NULL)
  225.     {
  226.         if((variable = FindVariable(varstore, name)) != NULL)
  227.         {
  228.             return variable->value;
  229.         }
  230.     }
  231.  
  232.     return NULL;
  233. }   
  234.  
  235. uint GetVariableType(VARSTORE *varstore, const char *name)
  236. {
  237.     VARIABLE *variable;
  238.  
  239.     if(name != NULL)
  240.     {
  241.         if((variable = FindVariable(varstore, name)) != NULL)
  242.         {
  243.             return variable->type;
  244.         }
  245.     }
  246.  
  247.     return VAR_TYPE_UNKNOWN;
  248. }
  249.  
  250. uint GetVariableFlag(VARSTORE *varstore, const char *name)
  251. {
  252.     VARIABLE *variable;
  253.  
  254.     if(name != NULL)
  255.     {
  256.         if((variable = FindVariable(varstore, name)) != NULL)
  257.         {
  258.             return variable->flag;
  259.         }
  260.     }
  261.  
  262.     return VAR_FLAG_UNKNOWN;
  263. }   
  264.  
  265. static void DestroyVariable(VARSTORE *varstore, VARIABLE *variable)
  266. {
  267.     /* if the variable has a destructor callback, do it */
  268.     if(variable->destructor != NULL)
  269.     {
  270.         variable->destructor(variable->name, variable->value, variable->type,
  271.             variable->flag, variable->param);
  272.     }
  273.  
  274.     /* if this is the last referenced variable, uncache it */
  275.     if(varstore->lastVariable == variable)
  276.     {
  277.         varstore->lastVariable = NULL;
  278.     }
  279.  
  280.     /* free the structure */
  281.     FreeMemory(variable);
  282. }
  283.  
  284. void ClearVariableList(VARSTORE *varstore)
  285. {
  286.     VARIABLE *ptr;
  287.     VARIABLE *next;
  288.     uint ctr;
  289.  
  290.     assert(varstore != NULL);
  291.  
  292.     /* have to walk the entire hash table to destroy each item */
  293.     for(ctr = 0; ctr < HASH_TABLE_SIZE; ctr++)
  294.     {
  295.         ptr = varstore->variableHashTable[ctr];
  296.         while(ptr != NULL)
  297.         {
  298.             next = ptr->next;
  299.             DestroyVariable(varstore, ptr);
  300.             ptr = next;
  301.         }
  302.         varstore->variableHashTable[ctr] = NULL;
  303.     }
  304. }   
  305.  
  306. BOOL RemoveVariable(VARSTORE *varstore, const char *name)
  307. {
  308.     VARIABLE *ptr;
  309.     VARIABLE *prev;
  310.     uint index;
  311.  
  312.     assert(varstore != NULL);
  313.  
  314.     if(name == NULL)
  315.     {
  316.         return FALSE;
  317.     }
  318.  
  319.     index = StringToHashTableIndex(name);
  320.  
  321.     prev = NULL;
  322.     ptr = varstore->variableHashTable[index];
  323.     while(ptr != NULL)
  324.     {
  325.         #if DEBUG
  326.         variableStringCompares++;
  327.         #endif
  328.  
  329.         if(stricmp(ptr->name, name) == 0)
  330.         {
  331.             /* found the variable */
  332.             /* unlink from the list */
  333.             if(prev != NULL)
  334.             {
  335.                 prev->next = ptr->next;
  336.             }
  337.             else
  338.             {
  339.                 varstore->variableHashTable[index] = ptr->next;
  340.             }
  341.  
  342.             /* destroy the variable structure */
  343.             DestroyVariable(varstore, ptr);
  344.  
  345.             return TRUE;
  346.         }
  347.  
  348.         prev = ptr;
  349.         ptr = ptr->next;
  350.     }
  351.  
  352.     return FALSE;
  353. }
  354.  
  355. BOOL VariableExists(VARSTORE *varstore, const char *name)
  356. {
  357.     return (FindVariable(varstore, name) != NULL) ? TRUE : FALSE;
  358. }
  359.  
  360. void *GetVariableParam(VARSTORE *varstore, const char *name)
  361. {
  362.     VARIABLE *var;
  363.  
  364.     if(name != NULL)
  365.     {
  366.         if((var = FindVariable(varstore, name)) != NULL)
  367.         {
  368.             return var->param;
  369.         }
  370.     }
  371.  
  372.     return NULL;
  373. }
  374.  
  375. static VARSTORE *FindTopmostContext(VARSTORE *varstore)
  376. {
  377.     VARSTORE *ptr;
  378.  
  379.     assert(varstore != NULL);
  380.  
  381.     ptr = varstore;
  382.     while(ptr->child != NULL)
  383.     {
  384.         assert(ptr->child->parent == ptr);
  385.         ptr = ptr->child;
  386.     }
  387.  
  388.     return ptr;
  389. }
  390.  
  391. void PushVariableStoreContext(VARSTORE *parent, VARSTORE *varstore)
  392. {
  393.     VARSTORE *ptr;
  394.  
  395.     assert(parent != NULL);
  396.     assert(varstore != NULL);
  397.     assert(varstore->parent == NULL);
  398.  
  399.     ptr = FindTopmostContext(parent);
  400.  
  401.     ptr->child = varstore;
  402.     varstore->parent = ptr;
  403.     varstore->child = NULL;
  404. }
  405.  
  406. VARSTORE *PopVariableStoreContext(VARSTORE *varstore)
  407. {
  408.     VARSTORE *ptr;
  409.  
  410.     assert(varstore != NULL);
  411.  
  412.     ptr = FindTopmostContext(varstore);
  413.  
  414.     /* unlink from parent and return current context */
  415.     ptr->parent->child = NULL;
  416.     ptr->parent = NULL;
  417.  
  418.     return ptr;
  419. }
  420.  
  421. VARSTORE *PeekVariableStoreContext(VARSTORE *varstore)
  422. {
  423.     return FindTopmostContext(varstore);
  424. }
  425.  
  426.